//
// SampleScene.cs
// 
// This file is part of the QuickStart Game Engine.  See http://www.codeplex.com/QuickStartEngine
// for license details.
//

using System;
using System.Collections.Generic;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;

namespace Alex_s_Dream_The_Toy_World
{
    /// <summary>
    /// A test scene demonstrating the physics of QuickStart.
    /// </summary>
    /// <remarks>Ideally we will eventually be able to create a scene with a level editor, and save the level into a file format (like XML)
    ///          and then we would read this file in to load a scene.</remarks>
    public class Beach : Scene
    {
        public int AntiGravityBoxEffectID = 0;

        public Beach(FrameworkCore game)
            : base(game)
        {
            
        }

        public override void LoadContent(Microsoft.Xna.Framework.Content.ContentManager contentManager)
        {
            this.LoadFog("EnvironmentalEffects/Fog/GrayLowLayingFog.xml");

            LoadTerrain();

            LoadLight();

            LoadSkyDome();

            //LoadShipModel();

            //LoadCharacter();

            // After Load Terrain, Enemy must stand on ground
            LoadEnemy();

            LoadRainParticleEmitter();
            //LoadSnowParticleEmitter();

            LoadWater();

            //BoxStack(7, new Vector3(1000.0f, 185.0f, 700.0f));
            //BoxAntiGrav(new Vector3(1000.0f, 185.0f, 730.0f), false);
            //BoxAntiGrav(new Vector3(1000.0f, 185.0f, 575.0f), true);

            // Caution: The NavMesh tech is not complete or ready, using it on a map any larger than 256x256 will
            //          use quite a bit of memory. Only comment this out if you plan on working on it. If so,
            //          pressing the 'P' key will display the NavMeshChunks.
            // Additionally: You will need to uncomment this line in Terrain.cs inside the initialize function:
            //              this.vertexList.Clear();
            //
            //LoadNavMesh();

            // This allows our scene to hear about messages, in case we want to do any scene-specific events.
            game.GameMessage += this.Game_GameMessage;  

            base.LoadContent(contentManager);
        }

        private void LoadEnemy()
        {
            #region Robot

            Robot robot = new Robot(this.game);
            robot.Name = "Dude";
            //robot.Position = new Vector3(1.0f, 187.0f, 1.0f);
            robot.Rotation = Matrix.CreateRotationY(0f);
            robot.Scale = 1.0f;
            robot.LoadModel("Take 001", "Models/" + "dude");

            // Get Terrain Entity
            MsgGetTerrainEntity getTerrainMsg = ObjectPool.Aquire<MsgGetTerrainEntity>();
            getTerrainMsg.UniqueTarget = robot.Game.TerrainID;
            robot.Game.SendMessage(getTerrainMsg);

            // Get Map
            robot.Position = getTerrainMsg.TerrainEntity.Map.ConvertMapPositionToNomalPosition(new System.Drawing.Point(5, 5));

            robot.LoadAI();

            if (this.game.SceneManager != null)
                this.game.SceneManager.AddEntity(robot);  // Add the entity to the scene manager

            #endregion

            #region Fish

            Fish fish = new Fish(this.game);
            fish.Name = "Duck";
            //robot.Position = new Vector3(1.0f, 187.0f, 1.0f);
            fish.Rotation = Matrix.CreateRotationY(0f);
            fish.Scale = 10.0f;
            fish.LoadModel("Swim", "Models/" + "FishModel");

            // Get Map
            fish.Position = getTerrainMsg.TerrainEntity.Map.ConvertMapPositionToNomalPosition(new System.Drawing.Point(10, 10));

            fish.LoadAI();

            if (this.game.SceneManager != null)
                this.game.SceneManager.AddEntity(fish);  // Add the entity to the scene manager

            #endregion
        }

        /// <summary>
        /// Message listener for all entities
        /// </summary>
        /// <param name="message">Incoming message</param>
        protected virtual void Game_GameMessage(IMessage message)
        {
            switch (message.Type)
            {
                case MessageType.ButtonDown:
                    {
                        MsgGamePadButtonPressed msgButtonDown = message as MsgGamePadButtonPressed;
                        message.TypeCheck(msgButtonDown);

                        switch (msgButtonDown.Button)
                        {
                            case Buttons.A:
                                {
                                    HandleActionPressed();
                                }
                                break;
                            default:
                                break;
                        }
                    }
                    break;
                case MessageType.KeyDown:
                    {
                        MsgKeyPressed msgKeyDown = message as MsgKeyPressed;
                        message.TypeCheck(msgKeyDown);

                        switch (msgKeyDown.Key)
                        {
                            case Keys.Space:
                                {
                                    HandleActionPressed();
                                }
                                break;
                            case Keys.B:
                                {
                                    this.game.DrawShadowMapTextureToScreen = !this.game.DrawShadowMapTextureToScreen;
                                }
                                break;
                            case Keys.M:
                                {
                                    MsgGetControlledEntity msgGetControl = ObjectPool.Aquire<MsgGetControlledEntity>();
                                    this.game.SendInterfaceMessage(msgGetControl, InterfaceType.SceneManager);

                                    // If a controlled entity is found
                                    if ( msgGetControl.ControlledEntityID != FrameworkCore.UniqueIDEmpty )
                                    {
                                        // Check whether or not the controlled entity is movable.
                                        MsgGetHasDynamicPhysics msgGetMovable = ObjectPool.Aquire<MsgGetHasDynamicPhysics>();
                                        msgGetMovable.UniqueTarget = msgGetControl.ControlledEntityID;
                                        this.game.SendMessage(msgGetMovable);

                                        // Toggle the controlled entity's movable state.
                                        MsgSetPhysicsMovableState msgSetMovable = ObjectPool.Aquire<MsgSetPhysicsMovableState>();
                                        msgSetMovable.Movable = !msgGetMovable.HasDynamicPhysics;
                                        msgSetMovable.UniqueTarget = msgGetControl.ControlledEntityID;
                                        this.game.SendMessage(msgSetMovable);
                                    }
                                }
                                break;
                            case Keys.O:
                                {
                                    if (this.game.TerrainID != FrameworkCore.UniqueIDEmpty)
                                    {
                                        MsgToggleDisplayBoundingBoxes msgToggleBoxes = ObjectPool.Aquire<MsgToggleDisplayBoundingBoxes>();
                                        msgToggleBoxes.UniqueTarget = this.game.TerrainID;
                                        this.game.SendMessage(msgToggleBoxes);
                                    }
                                }
                                break;
                            case Keys.F2:
                                {
                                    MsgGetRenderEntity msgGetRender = ObjectPool.Aquire<MsgGetRenderEntity>();
                                    this.game.SendInterfaceMessage(msgGetRender, InterfaceType.Camera);

                                    if (msgGetRender.EntityID != FrameworkCore.UniqueIDEmpty)
                                    {
                                        MsgSetParent msgSetParent = ObjectPool.Aquire<MsgSetParent>();
                                        msgSetParent.ParentEntity = null;
                                        msgSetParent.UniqueTarget = msgGetRender.EntityID;
                                        this.game.SendMessage(msgSetParent);
                                    }

                                    MsgSetControlledEntity msgSetControlled = ObjectPool.Aquire<MsgSetControlledEntity>();
                                    msgSetControlled.ControlledEntityID = FrameworkCore.UniqueIDEmpty;
                                    this.game.SendInterfaceMessage(msgSetControlled, InterfaceType.SceneManager);
                                }
                                break;
                            case Keys.Tab:
                                {
                                    MsgGetRenderEntity msgGetRender = ObjectPool.Aquire<MsgGetRenderEntity>();
                                    this.game.SendInterfaceMessage(msgGetRender, InterfaceType.Camera);

                                    if (msgGetRender.EntityID != FrameworkCore.UniqueIDEmpty)
                                    {
                                        MsgGetControlledEntity msgGetControlled = ObjectPool.Aquire<MsgGetControlledEntity>();
                                        this.game.SendInterfaceMessage(msgGetControlled, InterfaceType.SceneManager);

                                        bool ControlledEntityExists = (msgGetControlled.ControlledEntityID != FrameworkCore.UniqueIDEmpty);

                                        // Get all entities in the scene
                                        MsgGetEntityIDList msgGetIDList = ObjectPool.Aquire<MsgGetEntityIDList>();
                                        this.game.SendInterfaceMessage(msgGetIDList, InterfaceType.SceneManager);

                                        Int64[] entityList = msgGetIDList.EntityIDList;
                                        
                                        // If the scene root entity is the only entity, we can't do anything else here
                                        if (entityList.Length == 1)
                                            break;

                                        for (int i = 0; i < entityList.Length; ++i)
                                        {
                                            // If there is no controlled entity, or the entity we just found is the controlled entity
                                            if ( !ControlledEntityExists || (entityList[i] == msgGetControlled.ControlledEntityID) )
                                            {
                                                int EntityIndex = i;

                                                // If this entity is at the end of the list, grab the entity at the beginning of the list.
                                                if (EntityIndex == entityList.Length - 1)
                                                {
                                                    EntityIndex = FrameworkCore.FirstEntityIDAbleToBeAltered;
                                                }
                                                else
                                                {
                                                    ++EntityIndex;
                                                }

                                                // Make sure we don't set the camera as its own parent
                                                if (entityList[EntityIndex] == msgGetRender.EntityID)
                                                {
                                                    if (EntityIndex == entityList.Length - 1)
                                                    {
                                                        EntityIndex = FrameworkCore.FirstEntityIDAbleToBeAltered;
                                                    }
                                                    else
                                                    {
                                                        ++EntityIndex;
                                                    }

                                                    // If camera was chosen again, it is the only entity, so we can't do anything
                                                    if (entityList[EntityIndex] == msgGetRender.EntityID)
                                                    {
                                                        break;
                                                    }
                                                }

                                                MsgGetEntityByID msgGetEntity = ObjectPool.Aquire<MsgGetEntityByID>();
                                                msgGetEntity.EntityID = entityList[EntityIndex];
                                                this.game.SendInterfaceMessage(msgGetEntity, InterfaceType.SceneManager);

                                                if ( msgGetEntity.Entity != null )
                                                {
                                                    MsgSetControlledEntity msgSetControlled = ObjectPool.Aquire<MsgSetControlledEntity>();
                                                    msgSetControlled.ControlledEntityID = entityList[EntityIndex];
                                                    this.game.SendInterfaceMessage(msgSetControlled, InterfaceType.SceneManager);
                                                }

                                                break;
                                            }
                                        }
                                    }
                                }
                                break;
                            case Keys.Back:
                                {
                                    MsgGetEntityIDList msgGetIDList = ObjectPool.Aquire<MsgGetEntityIDList>();
                                    this.game.SendInterfaceMessage(msgGetIDList, InterfaceType.SceneManager);

                                    Int64[] entityList = msgGetIDList.EntityIDList;
                                    for (int i = entityList.Length - 1; i > FrameworkCore.FirstEntityIDAbleToBeAltered; --i)
                                    {
                                        if ( entityList[i] >= FrameworkCore.FirstEntityIDAbleToBeAltered )
                                        {
                                            MsgRemoveEntity msgRemEntity = ObjectPool.Aquire<MsgRemoveEntity>();
                                            msgRemEntity.EntityID = entityList[i];
                                            this.game.SendInterfaceMessage(msgRemEntity, InterfaceType.SceneManager);
                                        }
                                    }
                                }
                                break;
                            default:
                                break;
                        }
                    }
                    break;                
                default:
                    break;
            }
        }

        /// <summary>
        /// Creates a grid of boxes
        /// </summary>
        /// <param name="size">Grid size (side length)  size^2 boxes will be created.</param>
        /// <param name="spacing">Space between boxes.</param>
        /// <param name="offset">World position of box at (0, 0) in grid.</param>
        public void BoxGrid(int size, float spacing, Vector3 offset)
        {
            for(int i = 0; i < size; ++i)
            {
                for(int j = 0; j < size; ++j)
                {
                    Vector3 boxPos = offset + new Vector3(i * spacing, 0.0f, j * spacing);

                    // Create an entity, and give it a render and physics component
                    BaseEntity newEntity = new BaseEntity(this.game, boxPos, Matrix.Identity, 10.0f);
                    newEntity.Name = "Box from BoxGrid";

                    StaticRenderComponent newRenderComponent = new StaticRenderComponent(newEntity, "Models/unit_cube", "Material/SimpleColored");
                    newRenderComponent.modelColor = Color.Red;

                    PhysicsComponent newPhysComponent = new PhysicsComponent(newEntity, ShapeType.Box, 10.0f, true);

                    if (this.game.SceneManager != null)
                        this.game.SceneManager.AddEntity(newEntity);  // Add the entity to the scene manager
                }
            }
        }

        public void BoxStack(int totalRows, Vector3 offset)
        {
            int currentColumnMax = totalRows;

            // Use scale of box to determine positions from center along X axis
            const float BoxHalfExtent = 10.0f;

            for (int rows = 0; rows < totalRows; ++rows, --currentColumnMax)
            {
                for (int columns = 0; columns < currentColumnMax; ++columns)
                {
                    Vector3 boxPos = offset + new Vector3(columns * BoxHalfExtent, rows * BoxHalfExtent, 0.0f);
                    boxPos.X -= currentColumnMax * BoxHalfExtent * 0.5f;

                    // Create an entity, and give it a render and physics component
                    BaseEntity newEntity = new BaseEntity(this.game, boxPos, Matrix.Identity, 10.0f);
                    newEntity.Name = "Box From BoxStack";

                    StaticRenderComponent newRenderComponent = new StaticRenderComponent(newEntity, "Models/unit_cube", "Material/SimpleColored");
                    newRenderComponent.SetShadowingProperties(true, true);
                    newRenderComponent.modelColor = Color.Red;

                    PhysicsComponent newPhysComponent = new PhysicsComponent(newEntity, ShapeType.Box, 2, true);

                    // Boxes on the outside of the stack get smoke emitters
                    if (columns == 0 || columns == currentColumnMax - 1)
                    {
                        // Lets make each box a particle emitter
                        ParticleEmitterComponent smokeEmitter = new ParticleEmitterComponent(newEntity, "Material/Particles/SmokeParticle", "Particles/ParticleTrail");
                        smokeEmitter.InitializeEmitterSettings(Vector3.Zero, 2, Vector3.Zero);
                    }

                    if (this.game.SceneManager != null)
                        this.game.SceneManager.AddEntity(newEntity);  // Add the entity to the scene manager
                }
            }
        }

        public void BoxAntiGrav(Vector3 position, bool invisible)
        {
            BaseEntity newEntity = new BaseEntity(this.game, position, Matrix.Identity, 30.0f);
            newEntity.Name = "Anti-Gravity Volume";
            
            if (!invisible)
            {
                StaticRenderComponent newRenderComponent = new StaticRenderComponent(newEntity, "Models/unit_cube", "Material/SimpleColored");
                newRenderComponent.SetShadowingProperties(true, true);
                newRenderComponent.ModelColor = Color.Blue;
                newRenderComponent.Opacity = 0.60f;
            }

            PhantomPhysicsComponent newPhysComponent = new PhantomPhysicsComponent(newEntity, ShapeType.Box, 10.0f);
            CollisionTriggerComponent newCollTriggerComp = new CollisionTriggerComponent(newEntity);

            if (this.game.SceneManager != null)
                this.game.SceneManager.AddEntity(newEntity);  // Add the entity to the scene manager

            // Now that our anti-gravity box is in the world, lets set up the collision effect on it
            MsgAddCollisionEffect msgAddEffect = ObjectPool.Aquire<MsgAddCollisionEffect>();            
            msgAddEffect.EffectID = AntiGravityBoxEffectID;
            msgAddEffect.EffectType = CollisionEffectType.ConstantPushEffect;            
            msgAddEffect.UniqueTarget = newEntity.UniqueID;
            this.game.SendMessage(msgAddEffect);

            // This is where we set the effect properties (strength, direction, whether or not it is directional)         
            MsgInitCollisionEffect msgInitEffect = ObjectPool.Aquire<MsgInitCollisionEffect>();
            msgInitEffect.Direction = Vector3.UnitY;
            msgInitEffect.Strength = 10.0f;
            msgInitEffect.DirectionalEffect = true;
            msgInitEffect.EffectID = AntiGravityBoxEffectID;
            msgInitEffect.UniqueTarget = newEntity.UniqueID;
            this.game.SendMessage(msgInitEffect);
        }

        public void HandleActionPressed()
        {
            bool ShouldShootSphere = true;

            // If camera is attached to a character, then do not shoot a sphere because
            // the spacebar is also the 'jump' key for the character.
            MsgGetRenderEntity msgGetRender = ObjectPool.Aquire<MsgGetRenderEntity>();
            this.game.SendInterfaceMessage(msgGetRender, InterfaceType.Camera);

            if (msgGetRender.EntityID != FrameworkCore.UniqueIDEmpty)
            {
                MsgGetParentID msgGetParent = ObjectPool.Aquire<MsgGetParentID>();
                msgGetParent.UniqueTarget = msgGetRender.EntityID;
                this.game.SendMessage(msgGetParent);

                if (msgGetParent.ParentEntityID != FrameworkCore.UniqueIDEmpty)
                {
                    MsgGetIsACharacter msgIsChar = ObjectPool.Aquire<MsgGetIsACharacter>();
                    msgIsChar.UniqueTarget = msgGetParent.ParentEntityID;
                    this.game.SendMessage(msgIsChar);

                    if (msgIsChar.IsCharacter)
                    {
                        ShouldShootSphere = false;
                    }
                }
            }

            if (ShouldShootSphere)
            {
                ShootSphere();
            }
        }

        public void ShootSphere()
        {
            // We want to fire a sphere out from the camera

            // First we need to get the current rendering camera.
            MsgGetRenderEntity camMsg = ObjectPool.Aquire<MsgGetRenderEntity>();
            this.game.SendInterfaceMessage(camMsg, InterfaceType.Camera);

            // Make sure the camera's unique ID is valid
            if (camMsg.EntityID != FrameworkCore.UniqueIDEmpty)
            {
                // Now that we have our camera, grab it's forward vector
                MsgGetVectorForward getVectMsg = ObjectPool.Aquire<MsgGetVectorForward>();                
                getVectMsg.UniqueTarget = camMsg.EntityID;
                this.game.SendMessage(getVectMsg);

                MsgGetPosition getPosMsg = ObjectPool.Aquire<MsgGetPosition>();
                getPosMsg.UniqueTarget = camMsg.EntityID;
                this.game.SendMessage(getPosMsg);

                // We'll start the sphere just a bit in front of the camera
                Vector3 spherePos = getPosMsg.Position + (getVectMsg.Forward * 20);

                // Create an entity, and give it a render and physics component
                BaseEntity newEntity = new BaseEntity(this.game, spherePos, Matrix.Identity, 5.0f);
                newEntity.Name = "Sphere Projectile";

                StaticRenderComponent newRenderComponent = new StaticRenderComponent(newEntity, "Models/unit_sphere", "Material/SimpleColored");
                newRenderComponent.SetShadowingProperties(true, true);
                newRenderComponent.modelColor = Color.Orange;

                PhysicsComponent newPhysComponent = new PhysicsComponent(newEntity, ShapeType.Sphere, 10.0f, true);

                if (this.game.SceneManager != null)
                    this.game.SceneManager.AddEntity(newEntity);  // Add the entity to the scene manager

                // Now that our sphere is in the scene, let's give it a nudge
                MsgSetLinearVelocity setLinVelMsg = ObjectPool.Aquire<MsgSetLinearVelocity>();
                setLinVelMsg.LinearVelocity = (getVectMsg.Forward * 150.0f);
                setLinVelMsg.UniqueTarget = newEntity.UniqueID;
                this.game.SendMessage(setLinVelMsg);
            }
        }

        public void LoadTerrain()
        {
            Terrain newTerrain = new Terrain(this.game, LOD.High);
            newTerrain.Name = "Terrain";

            newTerrain.ElevationStrength = 75;

            newTerrain.Initialize("./Images/Heightmaps/Untitled2" /*TwoMountain2"*/ /*"gcanyon2"*/, 4, 4);

            PhysicsComponent terrainPhysicsComp = new PhysicsComponent(newTerrain, newTerrain.heightData, newTerrain.ScaleFactor);

            // Sets up the LOD arrays to allow for new LODs later on.
            newTerrain.SetupLODS();

            // Setup a very low LOD terrain. This will allow the water
            // component to use a very low detail terrain for faster
            // rendering. This terrain is not the default unless specified
            // seperately, so the terrain will continue to render at
            // its default setting, this merely sets up a second LOD terrain
            // for use by other components.
            switch (this.game.Settings.GraphicsLevel)
            {
                case GraphicsLevel.Highest:
                    // No LOD needed at highest settings
                    break;
                case GraphicsLevel.High:
                    newTerrain.AddNew(LOD.Med);
                    break;
                case GraphicsLevel.Med:
                case GraphicsLevel.Low:
                    newTerrain.AddNew(LOD.Low);
                    break;
            }

            if (this.game.SceneManager != null)
                this.game.SceneManager.AddEntity(newTerrain);
        }

        /// <summary>
        /// Load up a light for testing.        
        /// </summary>        
        private void LoadLight()
        {
            BaseEntity sceneLight = new BaseEntity(this.game);
            sceneLight.Name = "Scene Light";

            LightEmitterComponent lightComp = new LightEmitterComponent(sceneLight, "EnvironmentalEffects/Lights/DayLight.xml");

            if (this.game.SceneManager != null)
                this.game.SceneManager.AddEntity(sceneLight);

            lightComp.InitializeLightDirection();

            //ConstantRotationComponent constRotComp = new ConstantRotationComponent(sceneLight);

            //MsgSetConstantRotation setConstRotMsg = ObjectPool.Aquire<MsgSetConstantRotation>();
            //setConstRotMsg.Rotation = new Vector3(0.01f, 0.01f, 0.0f);    // We want the light to rotate a little bit about the Y axis each frame.
            //setConstRotMsg.UniqueTarget = sceneLight.UniqueID;
            //this.game.SendMessage(setConstRotMsg);
        }        

        private void LoadSkyDome()
        {
            BaseEntity sceneSky = new BaseEntity(this.game, new Vector3(0.0f, 0.0f, 0.0f), Matrix.CreateRotationZ(MathHelper.Pi), 2000.0f);
            sceneSky.Name = "Sky Dome";

            StaticRenderComponent renderComp = new StaticRenderComponent(sceneSky, "Models/dome", "Material/SkydomeSimple");
            renderComp.RenderOrder = PreferredRenderOrder.RenderFirst;
            renderComp.RendersAsSky = true;

            SkyDomeComponent skyDomeComp = new SkyDomeComponent(sceneSky);            

            // We hand off this entity to the scene manager before we send any messages to it. You cannot
            // send a message to an Entity that is not yet in the scene.
            if (this.game.SceneManager != null)
                this.game.SceneManager.AddEntity(sceneSky);

            // Now, lets attach the skydome to the current rendering camera.
            // First we need to get the current rendering camera.
            MsgGetRenderEntity camMsg = ObjectPool.Aquire<MsgGetRenderEntity>();
            this.game.SendInterfaceMessage(camMsg, InterfaceType.Camera);

            // If the ID we received is not empty, then we're good to go
            if (camMsg.EntityID != FrameworkCore.UniqueIDEmpty)
            {
                MsgAttachSkyToCamera attachCamMsg = ObjectPool.Aquire<MsgAttachSkyToCamera>();                
                attachCamMsg.CameraEntityID = camMsg.EntityID;
                attachCamMsg.UniqueTarget = sceneSky.UniqueID;
                this.game.SendMessage(attachCamMsg);
            }

            // Adding a constant rotation component to an object allows it to rotate a specific amount per frame.
            ConstantRotationComponent constRotComp = new ConstantRotationComponent(sceneSky);

            MsgSetConstantRotation setConstRotMsg = ObjectPool.Aquire<MsgSetConstantRotation>();            
            setConstRotMsg.Rotation = new Vector3(0.0f, 0.003f, 0.0f);    // We want the sky to rotate a little bit about the Y axis each frame.
            setConstRotMsg.UniqueTarget = sceneSky.UniqueID;
            this.game.SendMessage(setConstRotMsg);
        }

        private void LoadShipModel()
        {
            // Create an entity, and give it a render and physics component
            BaseEntity newEntity = new BaseEntity(this.game, new Vector3(1000.0f, 284.0f, 700.0f), Matrix.CreateRotationX(0.3f), 10.0f);
            newEntity.Name = "Space Ship";

            StaticRenderComponent newRenderComponent = new StaticRenderComponent(newEntity, "Models/ship", "Material/SimpleColored");
            newRenderComponent.SetShadowingProperties(true, true);
            newRenderComponent.modelColor = Color.Red;

            if (this.game.SceneManager != null)
                this.game.SceneManager.AddEntity(newEntity);  // Add the entity to the scene manager

            // You can create a triangle mesh physics component from a model this way if you don't want to use a render component's model to do it.
            // This way you can create a triangle mesh physics component without the need of a render component, or you can have your physics model
            // be different than the render model.
            //PhysicsComponent newPhysComponent = new PhysicsComponent(newEntity, "Models/ship", 2, false);

            // In this case we have a render component, and for this entity's physics we'll just use the render model. If we use this method, we need the
            // render component to be loaded first, and we need the entity to be added to the scene so we can send a message to the render component to
            // grab the model info.
            PhysicsComponent newPhysComponent = new PhysicsComponent(newEntity, ShapeType.TriangleMesh, 2, false);
        }

        private void LoadCharacter()
        {
            BaseEntity newEntity = new BaseEntity(this.game, new Vector3(750.3f, 190.2f, 794.6f), Matrix.CreateRotationY(-0.3f), 5.0f);
            newEntity.Name = "Character Test Shape";

            StaticRenderComponent newRenderComponent = new StaticRenderComponent(newEntity, "Models/unit_sphere", "Material/SimpleColored");
            newRenderComponent.SetShadowingProperties(true, true);
            newRenderComponent.modelColor = Color.Green;

            CharacterPhysicsComponent newPhysComponent = new CharacterPhysicsComponent(newEntity, ShapeType.Capsule, 5.0f);
            CharacterInputComponent newInputComponent = new CharacterInputComponent(newEntity);

            if (this.game.SceneManager != null)
                this.game.SceneManager.AddEntity(newEntity);  // Add the entity to the scene manager

            MsgSetControlledEntity setControlled = ObjectPool.Aquire<MsgSetControlledEntity>();            
            setControlled.ControlledEntityID = newEntity.UniqueID;
            this.game.SendInterfaceMessage(setControlled, InterfaceType.SceneManager);

            MsgLockCharacterRotationToCamera lockCharToCamMsg = ObjectPool.Aquire<MsgLockCharacterRotationToCamera>();            
            lockCharToCamMsg.LockRotation = true;
            lockCharToCamMsg.UniqueTarget = newEntity.UniqueID;
            this.game.SendMessage(lockCharToCamMsg);
        }

        private void LoadRainParticleEmitter()
        {
            // Lets find the render camera and attach a particle emitter to it.
            MsgGetRenderEntity msgGetRender = ObjectPool.Aquire<MsgGetRenderEntity>();
            this.game.SendInterfaceMessage(msgGetRender, InterfaceType.Camera);

            if ( msgGetRender.EntityID == FrameworkCore.UniqueIDEmpty )
                return;

            MsgGetEntityByID msgGetEntity = ObjectPool.Aquire<MsgGetEntityByID>();
            msgGetEntity.EntityID = msgGetRender.EntityID;
            this.game.SendInterfaceMessage(msgGetEntity, InterfaceType.SceneManager);

            if (msgGetEntity.Entity == null)
                return;

            ParticleEmitterComponent rainEmitter = new ParticleEmitterComponent(msgGetEntity.Entity, "Material/Particles/RainParticle", "Particles/RainSettings");

            // Give the emitter some settings.
            rainEmitter.InitializeEmitterSettings( new Vector3(0.0f, 250.0f, 0.0f), 1000, new Vector3( 250.0f, 10.0f, 250.0f ) );
        }

        private void LoadSnowParticleEmitter()
        {
            // Lets find the render camera and attach a particle emitter to it.
            MsgGetRenderEntity msgGetRender = ObjectPool.Aquire<MsgGetRenderEntity>();
            this.game.SendInterfaceMessage(msgGetRender, InterfaceType.Camera);

            if (msgGetRender.EntityID == FrameworkCore.UniqueIDEmpty)
                return;

            MsgGetEntityByID msgGetEntity = ObjectPool.Aquire<MsgGetEntityByID>();
            msgGetEntity.EntityID = msgGetRender.EntityID;
            this.game.SendInterfaceMessage(msgGetEntity, InterfaceType.SceneManager);

            if (msgGetEntity.Entity == null)
                return;

            ParticleEmitterComponent rainEmitter = new ParticleEmitterComponent(msgGetEntity.Entity, "Material/Particles/SnowParticle", "Particles/SnowSettings");

            // Give the emitter some settings.
            rainEmitter.InitializeEmitterSettings(new Vector3(0.0f, 100.0f, 0.0f), 1000, new Vector3(250.0f, 10.0f, 250.0f));
        }

        private void LoadWater()
        {
            BaseEntity newEntity = new BaseEntity(this.game, new Vector3(0.0f, 165.0f, 0.0f), Matrix.Identity, 1.0f);
            newEntity.Name = "Water Plane";

            int size = 4096;
            if (this.game.TerrainID != FrameworkCore.UniqueIDEmpty)
            {
                MsgGetTerrainProperties msgGetTerrainProps = ObjectPool.Aquire<MsgGetTerrainProperties>();
                msgGetTerrainProps.UniqueTarget = this.game.TerrainID;
                this.game.SendMessage(msgGetTerrainProps);

                size = msgGetTerrainProps.Size;
                size *= msgGetTerrainProps.TerrainScale;
            }

            WaterComponent waterComp = new WaterComponent(newEntity, size, size, "Material/Water");
            waterComp.SetWaterColor(new Color(0.0f, 0.1f, 0.2f, 1.0f));
            waterComp.Reflectivity = 0.7f;

            ConstantMovementComponent moveComp = new ConstantMovementComponent(newEntity);

            if (this.game.SceneManager != null)
                this.game.SceneManager.AddEntity(newEntity);  // Add the entity to the scene manager

            // Now that the entity is part of the scene, we can send it a message to give it movement parameters.
            MsgSetConstantMovement msgMove = ObjectPool.Aquire<MsgSetConstantMovement>();
            msgMove.MovementVector = Vector3.Up;
            msgMove.Frequency = 20.0f;
            msgMove.Amplitude = 5.0f;
            msgMove.UniqueTarget = newEntity.UniqueID;
            this.game.SendMessage(msgMove);
        }

        private void LoadNavMesh()
        {
            NavMesh mesh = new NavMesh(game);
            mesh.Name = "Nav Mesh";

            MsgGenerateNavMesh genNavMeshMessage = ObjectPool.Aquire<MsgGenerateNavMesh>();
            game.QueueMessage(genNavMeshMessage);

            if (this.game.SceneManager != null)
                this.game.SceneManager.AddEntity(mesh);
        }
    }
}
